use super::dao::{BaseDao, UpdateDao};
use crate::db::po::{
    self,
    user::{ActiveModel, Column, Entity, Model},
};
use sea_orm::{ColumnTrait, DatabaseConnection};
use sea_query::IntoCondition;

#[derive(Debug, Default, Clone, Eq, PartialEq)]
pub struct Filter {
    pub user_id: Option<String>,
    pub username: Option<String>,
}

impl IntoCondition for Filter {
    fn into_condition(self) -> sea_query::Condition {
        let mut condition = sea_query::Condition::all();

        if let Some(user_id) = self.user_id {
            condition = condition.add(Column::UserId.eq(user_id));
        }

        if let Some(username) = self.username {
            condition = condition.add(Column::Username.eq(username));
        }

        condition
    }
}

#[derive(Debug, Default, Clone, PartialEq)]
pub struct UpdateParams {
    pub description: po::ActiveValue<String>,
    pub password_crypto: po::ActiveValue<String>,
}

impl Into<ActiveModel> for UpdateParams {
    fn into(self) -> ActiveModel {
        ActiveModel {
            id: Default::default(),
            user_id: Default::default(),
            user_type: Default::default(),
            username: Default::default(),
            description: self.description,
            password_crypto_format: Default::default(),
            password_crypto: self.password_crypto,
            create_timestamp_millis: Default::default(),
            update_timestamp_millis: Default::default(),
        }
    }
}

#[async_trait::async_trait]
pub trait UserDao:
    BaseDao<
        Model = Model,
        ActiveModel = ActiveModel,
        Entity = Entity,
        Column = Column,
        Filter = Filter,
    > + UpdateDao<UpdateParams = UpdateParams>
{
}

#[derive(Clone)]
pub struct DefaultUserDao {
    db: DatabaseConnection,
}

impl DefaultUserDao {
    pub fn new(db: DatabaseConnection) -> Self {
        Self { db }
    }
}

#[async_trait::async_trait]
impl BaseDao for DefaultUserDao {
    type Model = Model;
    type ActiveModel = ActiveModel;
    type Entity = Entity;
    type Column = Column;
    type Filter = Filter;

    fn db(&self) -> &DatabaseConnection {
        &self.db
    }
}

#[async_trait::async_trait]
impl UpdateDao for DefaultUserDao {
    type UpdateParams = UpdateParams;
}

#[async_trait::async_trait]
impl UserDao for DefaultUserDao {}
